# 自定义一个类，类里面是各种请求方式
import logging

import allure
import jsonpath
import pymysql
import requests
from deepdiff import DeepDiff
from pymysql import cursors

from core.global_text import g_varial

gc = g_varial()
class Keywords:
    # 不知道要传多少参数，可以用**kwargs接收参数
    def requests_get(self,**kwargs):
        res = requests.get(**kwargs)
        # 把这个请求返回的值存入到全局变量中，方便给jsonpath封装方法获取
        gc.set_dict("currnet_res",res)
        return res
    def requests_post(self,**kwargs):
        res = requests.post(**kwargs)
        gc.set_dict("currnet_res", res)
        return res
    def requests_put(self,**kwargs):
        res = requests.put(**kwargs)
        gc.set_dict("currnet_res", res)
        return res
    def requests_delete(self,**kwargs):
        res = requests.delete(**kwargs)
        gc.set_dict("currnet_res", res)
        return res

    def assert_method(self,expect, actural, mark):
        """
        :param expect: 预期结果
        :param actural: 实际结果
        :param mark: 比较运算符
        :return:
        """
        try:
            if mark == "==":
                assert expect == actural
            elif mark == "!=":
                assert expect != actural
            elif mark == "<":
                assert expect < actural
            elif mark == ">":
                assert expect > actural
            elif mark == "<=":
                assert expect <= actural
            elif mark == ">=":
                assert expect >= actural
            elif mark == "in":
                assert expect in actural
        except Exception as e:
            logging.error(f"{mark}不符合要求",e)

    # jsonpath的二次封装
    @allure.step("提取数据")
    def ex_jsonData(self,**kwargs):
        """
        :param kwargs:
        response:返回值,
        EXVALUE:表达式,
        INDEX下标
        VARNAME:设置全局变量的变量名
        :return:
        """
        # 获得jsonpath的表达式 jsonpath.jsonpath(login_json, "$.msg")[0]
        # 返回值，我们可以把上面封装好的发送请求，返回值加到全局变量里面，再在这个方法中，从全局变量提取
        # 获得jsonpath的表达式
        EXPRESSION = kwargs.get("EXVALUE", None)
        # 获得下标值
        INDEX = kwargs.get("INDEX", None)
        # 如果INDEX为None，那就把下标值设置为0
        if INDEX is None:
            INDEX = 0
        try:
            response = gc.get_dic("currnet_res").json()
        except Exception as e:
            logging.error("========获取结果失败==============")

        # 最终执行jsonpath表达式，获得值 jsonpath.jsonpath(login_json, "$.msg")[0]
        ex_data = jsonpath.jsonpath(response,EXPRESSION)[INDEX]
        if type(ex_data) == list:
            ex_data = ex_data[0]
        if type(ex_data) == dict:
            ex_data = ex_data.values()
        # 把获得的值设置到全局变量里,key是用户输入的VARNAME变量名，value是上面提取出来的ex_data
        gc.set_dict(kwargs["VARNAME"],ex_data)
        return ex_data
    @allure.step("发送post请求--form_data表单请求")
    def request_post_form_data(self,**kwargs):
        url=kwargs.get("URL", None)
        params=kwargs.get("PARAMS", None)
        data=kwargs.get("DATA", None)
        headers=kwargs.get("HEADERS", None)
        request_data={
            "url":url,
            "params":params,
            "data":data,
            "headers":headers
        }
        response = self.requests_post(**request_data)
        # print("返回结果：",response.json())

    @allure.step("发送post请求--json请求")
    def request_post_json(self, **kwargs):
        url = kwargs.get("URL", None)
        params = kwargs.get("PARAMS", None)
        json_data = kwargs.get("DATA", None)
        headers = kwargs.get("HEADERS", None)
        request_data = {
            "url": url,
            "params": params,
            "json": json_data,
            "headers": headers
        }
        response = self.requests_post(**request_data)

    # 定义一个断言的方法，能够匹配yaml的写法
    @allure.step("文本断言")
    def assert_text_comparators(self,**kwargs):
        comparators={
            ">":lambda a,b:a>b,
            "<":lambda a,b:a<b,
            "==":lambda a,b:a==b,
            ">=":lambda a,b:a>=b,
            "<=":lambda a,b:a<=b,
            "!=":lambda a,b:a!=b,
        }
        message = kwargs.get('message',None)
        if kwargs["OP_STR"] not in comparators: # 判断标识符是否在上面的范围内，不在就抛出异常
            raise ValueError(f"没有该操作方式{kwargs['OP_STR']}")
        if not comparators[kwargs["OP_STR"]](kwargs["VALUES"],kwargs["EXPECTED"]):
            # if not comparators['==']("a","b") 调用上面的函数，传入标识符，后面的元组放置a,b两个参数去比较，
            # 比如传入 == 1，2 此时会返回False 回到条件判断就是if not False == if True，进入判断语句
            if message:
                raise AssertionError(message)
            else:
                raise AssertionError(f"{kwargs['VALUES']}{kwargs['OP_STR']}{kwargs['EXPECTED']}","断言失败")

    @allure.step("全量断言")
    def assert_json_DeepDiff(self,**kwargs):
        try:
            EXPECTEDJSON = kwargs["EXPECTEDJSON"]
            ACTUALJSON  = gc.get_dic("currnet_res").json()
            exclude_paths = kwargs.get("过滤字段", True)
            ignore_order = kwargs.get("忽略顺序", True) # 对列表有用
            ignore_string_case = kwargs.get("忽略大小写", True)

            screen_data = {"exclude_paths":exclude_paths,"ignore_order":ignore_order,"ignore_string_case":ignore_string_case}

            diff = DeepDiff(EXPECTEDJSON,ACTUALJSON,**screen_data)
        except Exception as e:
            assert False,f"全量断言失败，代码报错{e}"
        assert not diff,f"全量断言失败 {diff}"

    @allure.step("数据库提取")
    def assert_db(self,**kwargs):
        # 初始化一个字典config
        config = {"cursorclass": cursors.DictCursor}
        # 读取全局变量 - 根据选择的数据 读取指定的数据库配置 连接对应的数据库
        db_config = g_varial().get_dic("_database")["mysql001"]
        config.update(db_config)
        con = pymysql.connect(**config)
        cur = con.cursor()
        cur.execute(kwargs["SQL"])
        rs = cur.fetchall()
        cur.close()
        con.close()
        print("数据库查询结果:", rs)
        var_names = kwargs["引用变量"].split(",") # var_names = [id,username]
        result = {}
        # 下面的嵌套循环，是为了弄出这样的格式效果 id_1 = 8751,username_1 = jeremy1 id_2 = 8752,username_2 = jeremy2
        for i, data in enumerate(rs, start=1):
            for j, value in enumerate(var_names):
                result[f'{var_names[j]}_{i}'] = data.get(var_names[j])  # 根据变量名称找读取出来的内容
        g_varial().set_by_dict(result)
if __name__ == '__main__':
    pass